import {
    _decorator,
    Animation,
    CCFloat,
    Collider2D,
    Component,
    Contact2DType,
    director,
    math,
    RigidBody2D,
    SkeletalAnimationState,
    v3,
    Vec2,
    Vec3,
    Label,
    ProgressBar,
    tween,
    UIOpacity, Node,instantiate,Color
} from 'cc';
import {Constant} from '../../config/Constant';
import {AttackType, PlayerCon} from '../../core/controller/PlayerCon';
import {ActorProperty} from '../../core/entity/ActorProperty';
import {Projectile} from '../../core/projectile/Projectile';
import {logUtil} from "../util/logUtil";
import { AudioManager } from './AudioManager';
import {Effect} from "../fight/IEffectContainer";
import {LevelCon} from "../../core/controller/LevelCon";
import {ProjectileEmitter} from "../../core/projectile/ProjectileEmiter";
import {EffectCon} from "../../core/controller/EffectCon";
import {Pools} from "../entity/ao/Pools";
import {UIGame} from "../../ui/UIGame";

const {ccclass, property} = _decorator;


let tempVelocity: Vec2 = new Vec2()

/**
 * 角色和怪物的动画,碰撞,数据
 *
 * tips:
 *  放在对象根节点,子节点有Animation组件
 */
@ccclass('ActorActionManager')
export class ActorActionManager extends Component {

    //动画组件
    @property(Animation)
    animation: Animation | null = null;

    //当前状态
    currState: Constant | string = Constant.ACTION.Idle;

    //刚体
    rigidbody: RigidBody2D | null = null;

    //碰撞组件
    collider: Collider2D | null = null;

    //终点方向,单位向量
    destForward: Vec3 = v3()
    //原始数据
    data

    //移动速度
    @property(CCFloat)
    linearSpeed: number = 5;

    //角色属性
    actorProperty: ActorProperty = new ActorProperty();
    //场景
    scene
    //被施加的buff
    buffs:any[]=[]

    //日志控制器
    log = logUtil.instance
    logLevel = "ActorActionManager"
    //攻击数值预制体名称
    HpHitNumPrefabName="HpHitNumPrefab"

    start() {
        this.log.log(this.logLevel, `start`)
        this.log.log('test_fight', `[3:ActorActionManager:start]{标识:${this.node.uuid},hp:${this.actorProperty.hp},maxHp:${this.actorProperty.maxHp},attack:${this.actorProperty.attack},移动速度:${this.linearSpeed}}`);
        this.animation = this.node.children[0]?.getComponent(Animation);
        this.rigidbody = this.node.getComponent(RigidBody2D);
        this.collider = this.node.getComponent(Collider2D);
        this.scene = director.getScene();
        //如果动画完结,提供处理
        this.collider.on(Contact2DType.BEGIN_CONTACT, this.onTriggerEnter, this)
        if(this.animation){
            this.changeAttackSpeed(this.data.attackSpeed)
            this.animation.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
        }
        //如果有了则不再初始化
        if(this.HpHitNumPools.pools.size == 0){
            const poolCount = 1;

            let uIGame= LevelCon.instance.node.getComponent(UIGame)
            this.HpHitNumPools.newPool(
                this.HpHitNumPrefabName,
                (): Node => {
                    let node = instantiate(uIGame.HpHitNumPrefab);
                    node.active = false;
                    return node;
                },
                poolCount,
                (node: Node) => {
                    node.removeFromParent();
                }
            );
        }
    }

    onDestroy() {
        this.log.log(this.logLevel, `onDestroy`)
        this.collider?.off(Contact2DType.BEGIN_CONTACT, this.onTriggerEnter, this);
        this.animation?.off(Animation.EventType.FINISHED, this.onAnimationFinished, this);
    }

    /**
     * 变更状态
     * @param {Constant} state 状态字段
     * @param {boolean} end 结束后才能变更
     */
    changeState(state: Constant | string) {
        this.log.log(this.logLevel, `changeState`)
        if (this.currState == Constant.ACTION.Die) {
            return;
        }
        if (this.currState == Constant.ACTION.Run && state != Constant.ACTION.Run) {
            this.stopMove()
        }
        this.animation?.crossFade(state as string, 0.1);
        this.currState = state;
    }

    update(deltaTime: number) {
        this.log.log(this.logLevel, `changeState`, this.currState)
        switch (this.currState) {
            case Constant.ACTION.Run:
                this.doMove();
                break;
        }
    }

    onAnimationFinished(eventType: Animation.EventType, state: SkeletalAnimationState) {
        this.log.log(this.logLevel, `onAnimationFinished`)
        if (state.name == Constant.ACTION.Attack) {
            this.changeState(Constant.ACTION.Run);
        }

        if (state.name == Constant.ACTION.Run) {
            this.changeState(Constant.ACTION.Run);
        }
    }

    //region 各种状态
    /**
     * 右移
     */
    doMove() {
        this.log.log(this.logLevel, `doMove${tempVelocity.x}`)
        let speed = this.linearSpeed * this.destForward.length();
        tempVelocity.x = math.clamp(this.destForward.x, -1, 1) * speed;
        tempVelocity.y = math.clamp(this.destForward.y, -1, 1) * speed;
        this.log.log("ORCA", `${this.logLevel + 3}移动预测{
            节点id:${this.node.uuid},
            刚体速度:${tempVelocity},
            目标方向:${this.destForward},
        }`)
        this.rigidbody.linearVelocity = tempVelocity
    }

    stopMove() {
        this.rigidbody.linearVelocity = Vec2.ZERO;
        this.log.log(this.logLevel, `stopMove`)
    }

    /**
     * 远程攻击的碰撞事件
     * @param {Collider2D} self 自身
     * @param {Collider2D} other 投射物
     */
    onTriggerEnter(self: Collider2D, other: Collider2D) {
        this.log.log(this.logLevel, `碰撞行为{发起者:${this.node.name},self:${self.node.name},other:${other.node.name}}`)
        // 复用近战伤害数据

        if(other.node.getComponent(Projectile).projectProperty.expire==true){
            other.node.getComponent(Projectile).projectProperty.expire=false
            let actor = other.node.getComponent(Projectile).host.getComponent(PlayerCon).actor;
            this.hurt(actor.actorProperty.attack, actor,Constant.HURT_TYPE.Attack);
            //弓箭情况处理
            other.node.getComponent(Projectile).onTriggerEnter(other, self)
        }

    }
    /**
     * @param {number} baseDam   基础伤害
     * @param {number} critRate  暴击率 [0, 1]
     * @param {number} critMult  暴击倍率（默认 2.0）
     * @param {number} randVar   伤害浮动 ±randVar%
     * @returns {{damageTemp:number, isCritTemp:boolean}}
     */
    calcDamage(baseDam, critRate, critMult , randVar) {
        const crit = Math.random() < critRate;
        const mult = crit ? critMult : 1;
        const rand = 1 + (Math.random() * 2 - 1) * randVar;
        return {
            damageTemp: Math.round(baseDam * mult * rand),
            isCritTemp: crit
        };
    }

    /**
     * 近战攻击事件
     * @param {number} dam 收到伤害的数值
     * @param {ActorActionCon| null} hurtSource 伤害来源,判定升级用的
     * @param {string} hurtType 伤害方式
     */
    hurt(dam: number, hurtSource: ActorActionManager | null,hurtType?:string) {
        this.log.log(this.logLevel, `hurt`);
        this.changeState(Constant.ACTION.Hit);
        //受伤音效
        if(this.data){
            AudioManager.instance.playSfx(this.data.hitSfx);
        }
        //受伤特效
        var anim = this.node.children[2]?.getComponent(Animation)
        if(anim) anim.play(Constant.EFFECT.Explosion)

        const playerCon = this.node.getComponent(PlayerCon);
        //是否暴击,闪避
        let isCrit=false,isEvade=false;
        //region 伤害前信息
        const hurtSourcePlayerCon = hurtSource?.node.getComponent(PlayerCon);
        this.log.log('test_fight', `[1:ActorActionManager:hurt:伤害前信息:进攻方标识:${hurtSource?.node.uuid ?? '未知'}]
            {职业:${hurtSource?.data.CNname ?? '未知'},伤害:${dam},
            ${hurtSourcePlayerCon ? `[攻击距离:${hurtSourcePlayerCon.attackRange},视距:${hurtSourcePlayerCon.fov},避距:${hurtSourcePlayerCon.vo}]` : '无角色控制器'}
            hp:${hurtSource?.actorProperty.hp ?? '未知'},暴击率:${hurtSource?.actorProperty.critRate ?? '未知'},闪避:${hurtSource?.actorProperty.agi ?? '未知'},攻速:${hurtSource?.data.attackSpeed ?? '未知'},maxHp:${hurtSource?.actorProperty.maxHp ?? '未知'},attack:${hurtSource?.actorProperty.attack ?? '未知'},移动速度:${hurtSource?.linearSpeed ?? '未知'}}

            {职业:${this.data?.CNname ?? this.node.name},标识:${this.node.uuid},
            ${playerCon ? `[攻击距离:${playerCon.attackRange},视距:${playerCon.fov},避距:${playerCon.vo}]` : '无角色控制器'}
            hp:${this.actorProperty.hp},暴击率:${this.actorProperty.critRate ?? '未知'},闪避:${this.actorProperty.agi ?? '未知'},攻速:${this.data?.attackSpeed ?? '未知'},maxHp:${this.actorProperty.maxHp},attack:${this.actorProperty.attack},移动速度:${this.linearSpeed}}`
            );
        //endregion
        // zgnTodo 特殊处理免伤,特殊暴击处理,首miss
        if(playerCon&&Constant.HURT_TYPE.Attack==hurtType){
            if(playerCon.regime==Constant.DYNAMIC_RESOURCE.Actor.Forces2.Regime){
                let against=EffectCon.instance.skillList
                for (let i = 0; i < against.length; i++) {
                    if(!against[i].isBuff&&against[i].triggerWay==Constant.EFFECT.TriggerWay.BeforeHurt){
                        switch (against[i].logLevel){
                            case "shoubao":
                                isCrit=against[i].apply(hurtSource)
                                break;
                            default:
                                break;
                        }
                    }
                }

            }
            if(playerCon.regime==Constant.DYNAMIC_RESOURCE.Actor.Forces1.Regime){
                let against=EffectCon.instance.skillList

                for (let i = 0; i < against.length; i++) {
                    if(against[i].isBuff&&against[i].triggerWay==Constant.EFFECT.TriggerWay.BeforeHurt){
                        switch (against[i].logLevel){
                            case "mianshang":
                                dam=against[i].apply(dam)
                                break;
                            case "shoumiss":
                                isEvade=against[i].apply(dam)
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }

        if(isEvade||Math.random() < this.actorProperty.agi){
            hurtSource.updateHpHitUI(dam,4)
        }else{
            //伤害判定
            if (this.currState != Constant.ACTION.Die) {
                if(playerCon&&Constant.HURT_TYPE.Attack==hurtType){
                    if(isCrit){
                        const {damageTemp,isCritTemp}=this.calcDamage(dam, 1, Constant.GAME_SET.CritMult,Constant.GAME_SET.RandVar)
                        dam=damageTemp
                    }else{
                        const {damageTemp,isCritTemp}=this.calcDamage(dam, hurtSource?.actorProperty.critRate, Constant.GAME_SET.CritMult,Constant.GAME_SET.RandVar)
                        isCrit=isCritTemp
                        dam=damageTemp
                    }
                    //真伤处理
                    if(playerCon.regime==Constant.DYNAMIC_RESOURCE.Actor.Forces2.Regime){
                        let against=EffectCon.instance.skillList
                        for (let i = 0; i < against.length; i++) {
                            if(against[i].isBuff&&against[i].triggerWay==Constant.EFFECT.TriggerWay.MidHurt){
                                switch (against[i].logLevel){
                                    case "zhenshang":
                                        dam+=against[i].apply(this.actorProperty.maxHp)
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }

                    }
                    this.updateHpHitUI(dam,isCrit?2:1)
                }

                this.actorProperty.hp = parseFloat((this.actorProperty.hp-dam).toFixed(Constant.GAME_SET.NumFixed));
                //血条处理1
                this.updateHpBarUI()
                //region 伤害注释
                this.log.log('test_fight', `[2:ActorActionManager:hurt:扣血后]
                {职业:${this.data?.CNname ?? this.node.name},标识:${this.node.uuid},伤害:${dam},hp:${this.actorProperty.hp},maxHp:${this.actorProperty.maxHp},attack:${this.actorProperty.attack},移动速度:${this.linearSpeed}}`);
                //endregion

                if (this.actorProperty.hp <= 0) {
                    // 防御塔特殊处理
                    if (!playerCon) {
                        this.scheduleOnce(() => {
                            let isWood = this.node.name.includes("Wood")
                            if(isWood){
                                LevelCon.instance.activateTower(Constant.STATIC_NODE_PATH.Wood_Tower_Destroyed)
                                LevelCon.instance.deactivateTower(Constant.STATIC_NODE_PATH.Wood_Tower)
                            }else{
                                LevelCon.instance.activateTower(Constant.STATIC_NODE_PATH.Tower_Destroyed)
                                LevelCon.instance.deactivateTower(Constant.STATIC_NODE_PATH.Tower)
                            }

                            if (director.isPaused()) {
                                director.resume();
                            } else {
                                director.pause();
                            }
                        }, 0.1);
                    } else {
                        this.onDie();
                    }
                }
            }

            //zgnHelp buff2:仅针对怪物,平A后赋值
            if(playerCon&&Constant.HURT_TYPE.Attack==hurtType){
                this.log.log('test_fight', `[3:ActorActionManager:hurt:特效前:职业:${hurtSource?.data.CNname ?? '未知'},hp:${hurtSource?.actorProperty.hp ?? '未知'}通过[${hurtType}]${isCrit ? '暴击':''}对${this.node.uuid}造成${dam}伤害值]`);
                //敌人兵营debuff光环施加
                if(playerCon.regime==Constant.DYNAMIC_RESOURCE.Actor.Forces2.Regime){
                    let against=EffectCon.instance.skillList

                    for (let i = 0; i < against.length; i++) {
                        if(!against[i].isBuff&&against[i].triggerWay==Constant.EFFECT.TriggerWay.Hurt){
                            this.addBuff(against[i])
                        }
                        if(against[i].isBuff&&against[i].triggerWay==Constant.EFFECT.TriggerWay.Hurt){
                            hurtSource?.addBuff(against[i])
                        }
                    }
                }
                this.log.log('test_fight', `[4:ActorActionManager:hurt:特效后:职业:${hurtSource?.data.CNname ?? '未知'},hp:${hurtSource?.actorProperty.hp ?? '未知'}通过特效伤害${this.node.uuid}]`);
            }
        }
    }

    onDie() {
        this.log.log("fight", `${this.node.name}死亡`)
        if (this.currState == Constant.ACTION.Die) {
            return;
        }
        this.changeState(Constant.ACTION.Die);
        this.node.emit(Constant.ACOTR_EVENT_NAME.onKilled, this)
    }

    //zgnHelp 复活:战斗角色数据
    respawn() {
        this.log.log(this.logLevel, `respawn`)
        this.animation?.crossFade(Constant.ACTION.Idle, 0.1);

        //重置设置
        this.currState = Constant.ACTION.Idle;
        this.node.position=new Vec3(0,0,0)
        this.actorProperty.hp=this.actorProperty.maxHp
        this.linearSpeed=this.data.linearSpeed
        this.changeAttackSpeed(this.data.attackSpeed)

        //如果远程,箭矢回收
        let projectileEmitter=this.node.getComponent(ProjectileEmitter)
        if(projectileEmitter&&this.node.children.length>3){
            for (let i=3; i<this.node.children.length; i++){
                let projectileNode=this.node.children[i]
                if(projectileNode.name.includes("arrow")){
                    projectileEmitter.onProjectileDead(projectileNode.getComponent(Projectile))
                }
            }
        }

        //回收伤害数值
        let damageText=this.node.getComponent(UIOpacity)
        if(damageText&&this.node.children.length>3){
            for (let i=3; i<this.node.children.length; i++){
                let damageTextNode=this.node.children[i]
                if(damageTextNode.name.includes("DamageText")){
                    this.onHpHitDead(damageText.node)
                }
            }
        }

        // 数据恢复
        //zgnHelp buff3:清除buff
        for (let i = 0; i <this.buffs.length ; i++) {
            this.removeBuff(this.buffs[i].effect.id)
        }

        this.updateHpBarUI()
    }

    changeAttackSpeed(attackSpeed:number){
        if(this.animation){
            this.animation.getState(Constant.ACTION.Attack).speed = attackSpeed;
        }
    }
    /**
     * 对自身施加特效,无则施加,有(失效,激活;有效不管)
     * @param effect {Effect} 特效
     * @author zgn
     */
    addBuff(effect:Effect){
        let buff =this.buffs.find(b => b.effect.id == effect.id);
        if(buff){
            //每次触发
            if(!buff.duration){
                effect.apply(this)
            }
            //时限类
            if(!buff.active){
                effect.apply(this)
                buff.timerId=effect.timerId
                buff.active=true

                this.updateBuffUI()
            }
        }else{
            effect.apply(this)

            this.buffs.push({
                "timerId":effect.timerId,
                "effect":effect,
                "active":true
            })

            this.updateBuffUI()
        }
    }
    //字面移除
    removeBuff(id:number){
        let buff =this.buffs.find(b => b.effect.id == id);
        if(buff){
            clearTimeout(buff.timerId);
            buff.timerId=null
            buff.active=false
            buff.effect.remove(this)
            this.updateBuffUI()
        }
    }

    updateBuffUI(){
        this.node.children[2].children[0].getComponent(Label).string = this.buffs
            .filter(b => b.active)
            .map(b => b.effect.name)
            .join(',');
    }

    updateHpBarUI(){
        this.log.log(this.logLevel, `血条操作`);
        this.node.children[2].children[1].getComponent(ProgressBar).progress = this.actorProperty.hp/this.actorProperty.maxHp
    }
    //预制体对象池
    HpHitNumPools: Pools<string, Node> = new Pools();

    onHpHitDead(node: Node) {
        node.setScale(new Vec3(1, 1, 1))
        this.scheduleOnce(() => {
            node.active = false;
            this.HpHitNumPools.free(this.HpHitNumPrefabName, node);
        }, 0.1)

    }
    /**
     * 更新生命值和受击UI的显示效果
     * @param dam 受到的伤害值
     * @param type 伤害种类 1:普攻;2:暴击;3:回血;4:闪避
     */
    updateHpHitUI(dam:number,type:number){
        //预制体详细操作
        //取出预制体
        let node = this.HpHitNumPools.allocc(this.HpHitNumPrefabName)

        this.node.addChild(node);
        node.active = true;

        if(node.parent.scale.x<0&&node.scale.x>0){
            node.scale.set(-node.scale.x,node.scale.y)
        }
        // node.once(Constant.EVENT_NAME.onHpHitDead, this.onHpHitDead, node);

        // 获取显示伤害值的Label组件
        let label = node.getComponent(Label);
        label.string = dam+""; // 设置显示的伤害值
        switch (type) {
            case 1:
                label.color=Color.RED;
                break;
            case 2:
                label.color=Color.YELLOW;
                break;
            case 3:
                label.color=Color.GREEN;
                break;
            case 4:
                label.color=Color.GREEN;
                label.string = "MISS";
                break;
            default:
                break;
        }

        // 重置节点位置和透明度
        label.node.position= new Vec3(0, 0, 0);
        let Opacity=label.node.getComponent(UIOpacity);
        Opacity.opacity=255; // 设置为完全不透明

        // 1%的概率触发特殊效果
        if(Math.floor(Math.random() * 100) === 0){
        // 创建一个tween动画，使节点先放大并移动，然后恢复原始大小
            tween(node)
                .to(1, {scale: new Vec3(2, 2, 2), position: new Vec3(5, 5, 5)}) // 1秒内放大到2倍并移动到(5,5,5)
                .call(() => {
                    this.log.log(this.logLevel, `动画执行完成后调用回调函数`); }) // 动画执行完成后调用回调函数
                .by(1, {scale: new Vec3(-1, -1, -1)}, {easing: 'sineOutIn'}) // 使用正弦缓动效果缩小1倍
                .start() // 开始动画
        }

        // 创建伤害数字上升并放大的动画
        /*tween(Opacity)
            .to(1, {
                opacity: 0,
            }, {
                easing: 'quadOut' // 先快后慢的缓动效果
            })
            .start();*/

        tween(label.node)
            .to(1, {
                position: new Vec3(Math.floor(Math.random() * (40 - 20 + 1)) + 20, label.node.position.y+50, 0), // 向上移动50单位
                scale: new Vec3(label.node.scale.x*2, 2, 2), // 放大到2倍
            }, {
                easing: 'quadOut' // 先快后慢的缓动效果
            })
            .call(() => {
                this.onHpHitDead(node) // 回收节点到对象池
            })
            .start();
    }
    //endregion
}


